Imports System.ComponentModel
Imports System.Globalization
Imports System.Windows.Forms

Imports Vintasoft.Imaging
Imports Vintasoft.Imaging.VisualTools

Imports DemosCommonCode.Imaging.Codecs
Imports System.Drawing


Namespace Imaging
	' Properties: CanOpenFile, CanSaveFile, CanPrint, CanNavigate, ShowInstruments, SelectedPageIndex, PagesCount.
	' Events: OpenFile, SaveFile, Print, PageIndexChanged.
	Public Partial Class ImageViewerToolstrip
		Inherits ToolStrip

		#Region "Nested classes"

		Public Class PageIndexChangedEventArgs
			Inherits EventArgs
			Public SelectedPageIndex As Integer

			Public Sub New(pageIndex As Integer)
				Me.SelectedPageIndex = pageIndex
			End Sub
		End Class

		#End Region



		#Region "Enums"

		Public Enum Instrument
			None
			RectangularSelection
			EllipticalSelection
			CustomSelection
			Magnifier
			CropSelection
			DragAndDropSelection
			OverlayImage
			ZoomSelection
			Zoom
			Pan
			ScrollPages
			CompositeTool
		End Enum

		#End Region



		#Region "Fields"

		Private _imageViewer As ImageViewer = Nothing

		Private _zoomValues As Integer() = New Integer() {1, 5, 10, 25, 50, 75, _
			100, 125, 150, 200, 400, 600, _
			800, 1000}

		Private _canOpenFile As Boolean = True
		Private _canSaveFile As Boolean = True

		' Visual tools
		Private _rectangularSelection As RectangularSelectionToolWithCopyPaste
		Private _customSelection As CustomSelectionTool
		Private _ellipticalSelection As CustomSelectionTool
		Private _cropSelection As CropSelectionTool
		Private _dragNDropSelection As DragDropSelectionTool
		Private _overlayImage As OverlayImageTool
		Private _zoomSelection As ZoomSelectionTool
		Private _zoom As ZoomTool
		Private _magnifier As MagnifierTool
		Private _pan As PanTool
		Private _scrollPages As ScrollPages
		Private _compositeTool As CompositeVisualTool

		Private _imageScaleSelected As ToolStripMenuItem

		Private _openImageDialog As OpenFileDialog

		#End Region



		#Region "Constructors"

		Public Sub New()
			MyBase.New()
			InitializeComponent()

			_imageScaleSelected = normalToolStripMenuItem
			normalToolStripMenuItem.Checked = True

			_images_CollectionChangedEventThreadSafe = New Images_CollectionChangedThreadSafeDelegate(AddressOf Images_CollectionChangedSafely)

			tbRectangularSelection.Tag = Instrument.RectangularSelection
			tbMagnifier.Tag = Instrument.Magnifier
			tbCropSelection.Tag = Instrument.CropSelection
			tbDragAndDropSelection.Tag = Instrument.DragAndDropSelection
			tbZoomSelection.Tag = Instrument.ZoomSelection
			tbOverlayImage.Tag = Instrument.OverlayImage
			tbZoom.Tag = Instrument.Zoom
			tbPan.Tag = Instrument.Pan
			tbScrollPages.Tag = Instrument.ScrollPages
			tbCompositeTool.Tag = Instrument.CompositeTool
			tbCustomSelection.Tag = Instrument.CustomSelection
			tbEllipticalSelection.Tag = Instrument.EllipticalSelection

			_openImageDialog = New OpenFileDialog()
			CodecsFileFilters.SetFilters(_openImageDialog)
		End Sub

		#End Region



		#Region "Properties"

		<Browsable(True)> _
		Public Property ImageViewer() As Vintasoft.Imaging.ImageViewer
			Get
				Return _imageViewer
			End Get
			Set
				If _imageViewer IsNot Nothing Then
					' unsubscribe from the ImagesChanging/ImagesChanged events of the viewer
					RemoveHandler _imageViewer.ImagesChanging, New EventHandler(AddressOf imageViewer_ImagesChanging)
					RemoveHandler _imageViewer.ImagesChanged, New EventHandler(AddressOf imageViewer_ImagesChanged)
					' unsubscribe from the ImageCollectionChanged event of image collection of the viewer
					RemoveHandler _imageViewer.Images.ImageCollectionChanged, New EventHandler(Of ImageCollectionChangeEventArgs)(AddressOf Images_CollectionChangedSafely)
					' unsubscribe from the FocusedIndexChanged event of the viewer
					RemoveHandler _imageViewer.FocusedIndexChanged, New EventHandler(Of FocusedIndexChangedEventArgs)(AddressOf imageViewer_FocusedIndexChanged)
					' unsubscribe from the ZoomChanged event of the viewer
					RemoveHandler _imageViewer.ZoomChanged, New EventHandler(Of ZoomChangedEventArgs)(AddressOf imageViewer_ZoomChanged)
				End If

				_imageViewer = value

				If _imageViewer IsNot Nothing Then
					' subscribe to the ImagesChanging/ImagesChanged events of the viewer
					AddHandler _imageViewer.ImagesChanging, New EventHandler(AddressOf imageViewer_ImagesChanging)
					AddHandler _imageViewer.ImagesChanged, New EventHandler(AddressOf imageViewer_ImagesChanged)
					' subscribe to the ImageCollectionChanged event of image collection of the viewer
					AddHandler _imageViewer.Images.ImageCollectionChanged, New EventHandler(Of ImageCollectionChangeEventArgs)(AddressOf Images_CollectionChangedSafely)
					' subscribe to the FocusedIndexChanged event of the viewer
					AddHandler _imageViewer.FocusedIndexChanged, New EventHandler(Of FocusedIndexChangedEventArgs)(AddressOf imageViewer_FocusedIndexChanged)
					' subscribe to the ZoomChanged event of the viewer
					AddHandler _imageViewer.ZoomChanged, New EventHandler(Of ZoomChangedEventArgs)(AddressOf imageViewer_ZoomChanged)

					If UseImageViewerImages Then
						labelPagesCount.Text = PageCount.ToString(CultureInfo.InvariantCulture)
					End If

					_rectangularSelection = New RectangularSelectionToolWithCopyPaste()
					_customSelection = New CustomSelectionTool()
					_ellipticalSelection = New CustomSelectionTool()
					_cropSelection = New CropSelectionTool()
					_dragNDropSelection = New DragDropSelectionTool()
					_zoomSelection = New ZoomSelectionTool()
					_zoom = New ZoomTool()
					_magnifier = New MagnifierTool()
					_pan = New PanTool()
					_scrollPages = New ScrollPages()
					_overlayImage = New OverlayImageTool()


					SetNewSelectionRegion(New LassoSelectionRegion())

					_ellipticalSelection.Selection = New SimpleEllipticalSelectionRegion()
					_ellipticalSelection.BeginBuildingOnFirstClick = True

					_compositeTool = New CompositeVisualTool(_rectangularSelection, _scrollPages)
					tbCompositeTool.ToolTipText = _compositeTool.Name
				End If

				If _imageViewer IsNot Nothing Then
					imageViewer_FocusedIndexChanged(Me, New FocusedIndexChangedEventArgs(_imageViewer.FocusedIndex))
				End If
			End Set
		End Property


		Private _pixelToPixelEnabled As Boolean = True
		<Browsable(True)> _
		<DefaultValue(True)> _
		Public Property PixelToPixelEnabled() As Boolean
			Get
				Return _pixelToPixelEnabled
			End Get
			Set
				_pixelToPixelEnabled = value
				pixelToPixelToolStripMenuItem.Visible = value
			End Set
		End Property

		Private _useImageViewerImages As Boolean = True
		<Browsable(True)> _
		<DefaultValue(True)> _
		Public Property UseImageViewerImages() As Boolean
			Get
				Return _useImageViewerImages
			End Get
			Set
				_useImageViewerImages = value
			End Set
		End Property

		Private _associatedZoomTrackBar As TrackBar
		<Browsable(True)> _
		Public Property AssociatedZoomTrackBar() As TrackBar
			Get
				Return _associatedZoomTrackBar
			End Get
			Set
				If _associatedZoomTrackBar IsNot Nothing Then
					RemoveHandler _associatedZoomTrackBar.ValueChanged, New EventHandler(AddressOf _associatedZoomTrackBar_ValueChanged)
					RemoveHandler _associatedZoomTrackBar.Scroll, New EventHandler(AddressOf _associatedZoomTrackBar_Scroll)
				End If

				_associatedZoomTrackBar = value

				If _associatedZoomTrackBar IsNot Nothing Then
					AddHandler _associatedZoomTrackBar.ValueChanged, New EventHandler(AddressOf _associatedZoomTrackBar_ValueChanged)
					AddHandler _associatedZoomTrackBar.Scroll, New EventHandler(AddressOf _associatedZoomTrackBar_Scroll)
				End If
			End Set
		End Property

		<Browsable(True)> _
		Public Property CanOpenFile() As Boolean
			Get
				Return _canOpenFile
			End Get
			Set
				tbOpen.Visible = InlineAssignHelper(_canOpenFile, value)

				toolStripSeparator1.Visible = (value OrElse CanSaveFile) And CanPrint
				toolStripSeparatorPrint.Visible = value OrElse CanSaveFile OrElse CanPrint
			End Set
		End Property

		<Browsable(True)> _
		Public Property CanSaveFile() As Boolean
			Get
				Return _canSaveFile
			End Get
			Set
				tbSave.Visible = InlineAssignHelper(_canSaveFile, value)

				toolStripSeparator1.Visible = (CanOpenFile OrElse value) And CanPrint
				toolStripSeparatorPrint.Visible = CanOpenFile OrElse value OrElse CanPrint
			End Set
		End Property

		<Browsable(True)> _
		Public Property SaveButtonEnabled() As Boolean
			Get
				Return tbSave.Enabled
			End Get
			Set
				tbSave.Enabled = value
			End Set
		End Property

		Private _canScan As Boolean = False
		<DefaultValue(False)> _
		Public Property CanScan() As Boolean
			Get
				Return _canScan
			End Get
			Set
				tbScan.Visible = InlineAssignHelper(_canScan, value)

				toolStripSeparator2.Visible = (CanOpenFile OrElse CanSaveFile) AndAlso value
				toolStripSeparator1.Visible = (CanOpenFile OrElse CanSaveFile) AndAlso value
				toolStripSeparatorPrint.Visible = CanOpenFile OrElse CanSaveFile OrElse value
			End Set
		End Property

		Private _canPrint As Boolean = True
		Public Property CanPrint() As Boolean
			Get
				Return _canPrint
			End Get
			Set
				tbPrint.Visible = InlineAssignHelper(_canPrint, value)

				toolStripSeparator1.Visible = (CanOpenFile OrElse CanSaveFile) AndAlso value
				toolStripSeparatorPrint.Visible = CanOpenFile OrElse CanSaveFile OrElse value
			End Set
		End Property

		Public Property PrintButtonEnabled() As Boolean
			Get
				Return tbPrint.Enabled
			End Get
			Set
				tbPrint.Enabled = value
			End Set
		End Property

		<Browsable(True)> _
		Public Property CanNavigate() As Boolean
			Get
				Return toolStripSeparatorNavigation.Visible
			End Get
			Set
				tbFirstPage.Visible = InlineAssignHelper(tbPreviousPage.Visible, InlineAssignHelper(textBoxPages.Visible, InlineAssignHelper(labelSlash.Visible, InlineAssignHelper(labelPagesCount.Visible, InlineAssignHelper(tbNextPage.Visible, InlineAssignHelper(tbLastPage.Visible, InlineAssignHelper(toolStripSeparatorNavigation.Visible, value)))))))
			End Set
		End Property

		Private _showInstruments As Boolean = False
		<Browsable(True)> _
		<DefaultValue(False)> _
		Public Property ShowInstruments() As Boolean
			Get
				Return _showInstruments
			End Get
			Set
				_showInstruments = value
				tbNone.Visible = value
				tbRectangularSelection.Visible = value
				tbEllipticalSelection.Visible = value
				tbCustomSelection.Visible = value
				tbMagnifier.Visible = value
				tbCropSelection.Visible = value
				tbOverlayImage.Visible = value
				tbDragAndDropSelection.Visible = value
				tbZoomSelection.Visible = value
				tbZoom.Visible = value
				tbPan.Visible = value
				tbScrollPages.Visible = value
				tbCompositeTool.Visible = value
				toolStripSeparatorInstruments.Visible = value
				visualToolInfo.Visible = value
			End Set
		End Property

		Private _showSelectionInstruments As Boolean = False
		<Browsable(True)> _
		<DefaultValue(False)> _
		Public Property ShowSelectionInstruments() As Boolean
			Get
				Return _showSelectionInstruments
			End Get
			Set
				_showSelectionInstruments = value
				tbNone.Visible = value
				tbRectangularSelection.Visible = value
				tbEllipticalSelection.Visible = value
				tbCustomSelection.Visible = value
				toolStripSeparatorInstruments.Visible = value
				visualToolInfo.Visible = value
			End Set
		End Property

		Private _selectedPageIndex As Integer
		Public Property SelectedPageIndex() As Integer
			Get
				Return _selectedPageIndex
			End Get
			Set
				UpdateSelectedPageIndex(value)
			End Set
		End Property

		Private _pageCount As Integer
		Public Property PageCount() As Integer
			Get
				If UseImageViewerImages Then
					If _imageViewer IsNot Nothing Then
						Return _imageViewer.Images.Count
					Else
						Return 0
					End If
				Else
					Return _pageCount
				End If
			End Get
			Set
				If Not UseImageViewerImages Then
					If value >= 0 AndAlso value <> PageCount Then
						_pageCount = value
						labelPagesCount.Text = PageCount.ToString(CultureInfo.InvariantCulture)

						If _selectedPageIndex >= PageCount Then
							UpdateSelectedPageIndex(PageCount - 1)
						ElseIf _selectedPageIndex >= 0 Then
							UpdateSelectedPageIndex(_selectedPageIndex)
						ElseIf PageCount > 0 Then
							UpdateSelectedPageIndex(0)
						End If
					End If
				End If
			End Set
		End Property

		#End Region



		#Region "Methods"

		#Region "Main strip"

		Private Sub tbOpen_Click(sender As Object, e As System.EventArgs)
			RaiseEvent OpenFile(sender, e)
		End Sub

		Private Sub tbSave_Click(sender As Object, e As System.EventArgs)
			RaiseEvent SaveFile(sender, e)
		End Sub

		Private Sub tbScan_Click(sender As Object, e As System.EventArgs)
			RaiseEvent Scan(sender, e)
		End Sub

		Private Sub tbPrint_Click(sender As Object, e As System.EventArgs)
			RaiseEvent Print(sender, e)
		End Sub

		#End Region


		#Region "Navigation"

		Private Sub tbFirstPage_Click(sender As Object, e As System.EventArgs)
			SelectedPageIndex = 0
		End Sub

		Private Sub tbPreviousPage_Click(sender As Object, e As System.EventArgs)
			SelectedPageIndex -= 1
		End Sub

		Private Sub tbNextPage_Click(sender As Object, e As System.EventArgs)
			SelectedPageIndex += 1
		End Sub

		Private Sub tbLastPage_Click(sender As Object, e As System.EventArgs)
			SelectedPageIndex = PageCount - 1
		End Sub

		Private Sub textBoxPages_KeyPress(sender As Object, e As KeyPressEventArgs)
			If e.KeyChar = ControlChars.Cr Then
				' enter
				Dim value As Integer
				If Integer.TryParse(DirectCast(sender, ToolStripTextBox).Text, value) AndAlso value > 0 AndAlso value <= PageCount Then
					SelectedPageIndex = value - 1
				Else
					UpdateSelectedPageIndex(_selectedPageIndex)
				End If
			End If
		End Sub

		#End Region


		#Region "Scale mode"

		Private Sub UpdateTextBoxZoom()
			zoomTextBox.Text = [String].Format(CultureInfo.InvariantCulture, "{0}%", _imageViewer.Zoom)
		End Sub

		Private Sub zoomOutStripButton_Click(sender As Object, e As System.EventArgs)
			If _imageViewer.Zoom > _zoomValues(0) Then
				'  Min value.
				_imageScaleSelected.Checked = False
				_imageViewer.SizeMode = ImageSizeMode.Zoom

				Dim index As Integer = 0
				While index < _zoomValues.Length AndAlso _zoomValues(index) < _imageViewer.Zoom
					index += 1
				End While
				_imageViewer.Zoom = _zoomValues(index - 1)

				UpdateTextBoxZoom()
			End If
		End Sub

		Private Sub zoomInStripButton_Click(sender As Object, e As System.EventArgs)
			If _imageViewer.Zoom < _zoomValues(_zoomValues.Length - 1) Then
				'  Max value.
				_imageScaleSelected.Checked = False
				_imageViewer.SizeMode = ImageSizeMode.Zoom

				Dim index As Integer = 0
				While _zoomValues(index) <= _imageViewer.Zoom
					index += 1
				End While
				_imageViewer.Zoom = _zoomValues(index)

				UpdateTextBoxZoom()
			End If
		End Sub

		Private Sub zoomTextBox_KeyPress(sender As Object, e As KeyPressEventArgs)
			If e.KeyChar = ControlChars.Cr Then
				' enter
				Dim sourceText As String = DirectCast(sender, ToolStripTextBox).Text.Replace("%", "")

				_imageScaleSelected.Checked = False
				_imageViewer.SizeMode = ImageSizeMode.Zoom

				Dim value As Integer
				If Integer.TryParse(sourceText, value) AndAlso value > 0 Then
					_imageViewer.Zoom = value
				End If

				UpdateTextBoxZoom()
			End If
		End Sub

		Private Sub ImageScale_Click(sender As Object, e As EventArgs)
			_imageScaleSelected.Checked = False
			_imageScaleSelected = DirectCast(sender, ToolStripMenuItem)

			If _imageScaleSelected Is normalToolStripMenuItem Then
				_imageViewer.SizeMode = ImageSizeMode.Normal
			ElseIf _imageScaleSelected Is bestFitToolStripMenuItem Then
				_imageViewer.SizeMode = ImageSizeMode.BestFit
			ElseIf _imageScaleSelected Is fitToWidthToolStripMenuItem Then
				_imageViewer.SizeMode = ImageSizeMode.FitToWidth
			ElseIf _imageScaleSelected Is fitToHeightToolStripMenuItem Then
				_imageViewer.SizeMode = ImageSizeMode.FitToHeight
			ElseIf _imageScaleSelected Is scaleToolStripMenuItem Then
				_imageViewer.SizeMode = ImageSizeMode.Zoom
			ElseIf _imageScaleSelected Is scale25ToolStripMenuItem Then
				_imageViewer.SizeMode = ImageSizeMode.Zoom
				_imageViewer.Zoom = 25
			ElseIf _imageScaleSelected Is scale50ToolStripMenuItem Then
				_imageViewer.SizeMode = ImageSizeMode.Zoom
				_imageViewer.Zoom = 50
			ElseIf _imageScaleSelected Is scale100ToolStripMenuItem Then
				_imageViewer.SizeMode = ImageSizeMode.Zoom
				_imageViewer.Zoom = 100
			ElseIf _imageScaleSelected Is scale200ToolStripMenuItem Then
				_imageViewer.SizeMode = ImageSizeMode.Zoom
				_imageViewer.Zoom = 200
			ElseIf _imageScaleSelected Is scale400ToolStripMenuItem Then
				_imageViewer.SizeMode = ImageSizeMode.Zoom
				_imageViewer.Zoom = 400
			ElseIf _imageScaleSelected Is pixelToPixelToolStripMenuItem Then
				_imageViewer.SizeMode = ImageSizeMode.PixelToPixel
			End If

			_imageScaleSelected.Checked = True

			UpdateTextBoxZoom()
		End Sub

		#End Region


		#Region "Visual tools"

		Private Sub SetNewSelectionRegion(region As SelectionRegionBase)
			If TypeOf region Is EllipticalSelectionRegion Then
				tbCustomSelection.Image = tsEllipseSelection.Image
			ElseIf TypeOf region Is LassoSelectionRegion Then
				tbCustomSelection.Image = tsLassoSelection.Image
			ElseIf TypeOf region Is CurvilinearSelectionRegion Then
				tbCustomSelection.Image = tsCurvesSelection.Image
			ElseIf TypeOf region Is RectangularSelectionRegion Then
				tbCustomSelection.Image = tsRectangleSelection.Image
			ElseIf TypeOf region Is PolygonalSelectionRegion Then
				tbCustomSelection.Image = tsPolygonSelection.Image
			End If
			_customSelection.Selection = region
			_customSelection.BeginBuilding()
		End Sub

		Private Sub tsSelectSelection_Click(sender As Object, e As System.EventArgs)
			If sender Is tsCurvesSelection Then
				SetNewSelectionRegion(New CurvilinearSelectionRegion())
			ElseIf sender Is tsEllipseSelection Then
				SetNewSelectionRegion(New EllipticalSelectionRegion())
			ElseIf sender Is tsLassoSelection Then
				SetNewSelectionRegion(New LassoSelectionRegion())
			ElseIf sender Is tsPolygonSelection Then
				SetNewSelectionRegion(New PolygonalSelectionRegion())
			ElseIf sender Is tsRectangleSelection Then
				SetNewSelectionRegion(New RectangularSelectionRegion())
			End If
		End Sub

		Private Sub Instrument_Click(sender As Object, e As System.EventArgs)
			tbNone.Checked = False
			tbRectangularSelection.Checked = False
			tbMagnifier.Checked = False
			tbCropSelection.Checked = False
			tbDragAndDropSelection.Checked = False
			tbZoomSelection.Checked = False
			tbZoom.Checked = False
			tbPan.Checked = False
			tbScrollPages.Checked = False
			tbCompositeTool.Checked = False
			tbEllipticalSelection.Checked = False
			tbOverlayImage.Checked = False

			Dim buttonSender As ToolStripButton = TryCast(sender, ToolStripButton)
			If buttonSender IsNot Nothing Then
				buttonSender.Checked = True
			End If

			visualToolInfo.Text = ""
			Dim visualToolInfoTextForSelection As String = "X=0, Y=0, Width=0, Height=0"

			' if the image viewer has visual tool (previous)
			If _imageViewer.VisualTool IsNot Nothing Then
				' unsubscribe from events of visual tool
				RemoveHandler _imageViewer.VisualTool.ImageLoadingException, New EventHandler(Of ExceptionEventArgs)(AddressOf VisualTool_ImageLoadingException)
			End If

			Dim rectangularSelection As RectangularSelectionTool = TryCast(_imageViewer.VisualTool, RectangularSelectionTool)
			If rectangularSelection IsNot Nothing Then
				RemoveHandler rectangularSelection.SelectionChanged, New EventHandler(Of SelectionChangedEventArgs)(AddressOf visualTool_RectangularSelectionChanged)
			End If
			Dim customSelection As CustomSelectionTool = TryCast(_imageViewer.VisualTool, CustomSelectionTool)
			If customSelection IsNot Nothing Then
				RemoveHandler customSelection.SelectionChanged, New EventHandler(Of CustomSelectionChangedEventArgs)(AddressOf visualTool_CustomSelectionChanged)
			End If

			If _overlayImage.Image IsNot Nothing Then
				Dim image As VintasoftImage = _overlayImage.Image
				_overlayImage.Image = Nothing
				image.Dispose()
			End If

			'
			If buttonSender Is tbNone Then
				_imageViewer.VisualTool = Nothing
				Return
			End If

			Dim selectedInstrument As Instrument = CType(DirectCast(sender, ToolStripItem).Tag, Instrument)

			'
			Select Case selectedInstrument
				Case Instrument.CropSelection
					_imageViewer.VisualTool = _cropSelection
					visualToolInfo.Text = visualToolInfoTextForSelection
					Exit Select

				Case Instrument.DragAndDropSelection
					_imageViewer.VisualTool = _dragNDropSelection
					visualToolInfo.Text = visualToolInfoTextForSelection
					Exit Select

				Case Instrument.Magnifier
					_imageViewer.VisualTool = _magnifier
					Exit Select

				Case Instrument.None
					_imageViewer.VisualTool = Nothing
					Exit Select

				Case Instrument.Pan
					_imageViewer.VisualTool = _pan
					Exit Select

				Case Instrument.RectangularSelection
					_imageViewer.VisualTool = _rectangularSelection
					visualToolInfo.Text = visualToolInfoTextForSelection
					Exit Select

				Case Instrument.CustomSelection
					If _imageViewer.VisualTool IsNot _customSelection Then
						Dim prevVisual As VisualTool = _imageViewer.VisualTool
						_imageViewer.VisualTool = _customSelection
						If TypeOf prevVisual Is CustomSelectionTool OrElse TypeOf prevVisual Is RectangularSelectionToolWithCopyPaste Then
							_customSelection.Selection = Nothing
						End If
					End If
					Exit Select

				Case Instrument.EllipticalSelection
					If _imageViewer.VisualTool IsNot _ellipticalSelection Then
						Dim prevVisual As VisualTool = _imageViewer.VisualTool
						_imageViewer.VisualTool = _ellipticalSelection
						If TypeOf prevVisual Is CustomSelectionTool OrElse TypeOf prevVisual Is RectangularSelectionToolWithCopyPaste Then
							_ellipticalSelection.Selection = Nothing
						End If
					End If
					Exit Select

				Case Instrument.Zoom
					_imageViewer.VisualTool = _zoom
					Exit Select

				Case Instrument.ZoomSelection
					_imageViewer.VisualTool = _zoomSelection
					visualToolInfo.Text = visualToolInfoTextForSelection
					Exit Select

				Case Instrument.OverlayImage
					_imageViewer.VisualTool = Nothing
					_imageViewer.VisualTool = _overlayImage
					If _openImageDialog.ShowDialog() = DialogResult.OK Then
						Try
							_overlayImage.Image = New VintasoftImage(_openImageDialog.FileName)
						Catch ex As Exception
							DemosTools.ShowErrorMessage(ex)
						End Try
					End If
					Exit Select

				Case Instrument.ScrollPages
					_imageViewer.VisualTool = _scrollPages

					If Not _imageViewer.Focused Then
						_imageViewer.Focus()
					End If

					Exit Select

				Case Instrument.CompositeTool
					_imageViewer.VisualTool = _compositeTool

					If Not _imageViewer.Focused Then
						_imageViewer.Focus()
					End If

					Exit Select
			End Select

			' if the image viewer has visual tool (new)
			If _imageViewer.VisualTool IsNot Nothing Then
				' subscribe from events of visual tool
				AddHandler _imageViewer.VisualTool.ImageLoadingException, New EventHandler(Of ExceptionEventArgs)(AddressOf VisualTool_ImageLoadingException)
			End If

			rectangularSelection = TryCast(_imageViewer.VisualTool, RectangularSelectionTool)
			If rectangularSelection IsNot Nothing Then
				AddHandler rectangularSelection.SelectionChanged, New EventHandler(Of SelectionChangedEventArgs)(AddressOf visualTool_RectangularSelectionChanged)
			End If
			customSelection = TryCast(_imageViewer.VisualTool, CustomSelectionTool)
			If customSelection IsNot Nothing Then
				AddHandler customSelection.SelectionChanged, New EventHandler(Of CustomSelectionChangedEventArgs)(AddressOf visualTool_CustomSelectionChanged)
			End If
		End Sub

		#End Region


		#Region "Event handlers of image viewer (thread safe)"

		Private Sub imageViewer_ImagesChanging(sender As Object, e As EventArgs)
			If UseImageViewerImages Then
				If _imageViewer IsNot Nothing Then
					' unsubscribe from the ImageCollectionChanged event of image collection of the viewer
					RemoveHandler _imageViewer.Images.ImageCollectionChanged, New EventHandler(Of ImageCollectionChangeEventArgs)(AddressOf Images_CollectionChangedSafely)
				End If
			End If
		End Sub

		Private Sub imageViewer_ImagesChanged(sender As Object, e As EventArgs)
			If UseImageViewerImages Then
				' subscribe to the ImageCollectionChanged event of image collection of the viewer
				AddHandler _imageViewer.Images.ImageCollectionChanged, New EventHandler(Of ImageCollectionChangeEventArgs)(AddressOf Images_CollectionChangedSafely)
			End If
		End Sub

		Private Sub imageViewer_FocusedIndexChanged(sender As Object, e As FocusedIndexChangedEventArgs)
			Dim buttonsEnabled As Boolean = _imageViewer IsNot Nothing AndAlso e.FocusedIndex >= 0
			If tbNone.Enabled <> buttonsEnabled Then
				' Navigation
				tbFirstPage.Enabled = buttonsEnabled
				tbPreviousPage.Enabled = buttonsEnabled
				textBoxPages.Enabled = buttonsEnabled
				tbNextPage.Enabled = buttonsEnabled
				tbLastPage.Enabled = buttonsEnabled
				' Instruments
				tbNone.Enabled = buttonsEnabled
				tbRectangularSelection.Enabled = buttonsEnabled
				tbEllipticalSelection.Enabled = buttonsEnabled
				tbCustomSelection.Enabled = buttonsEnabled
				tbMagnifier.Enabled = buttonsEnabled
				tbOverlayImage.Enabled = buttonsEnabled
				tbCropSelection.Enabled = buttonsEnabled
				tbDragAndDropSelection.Enabled = buttonsEnabled
				tbZoomSelection.Enabled = buttonsEnabled
				tbZoom.Enabled = buttonsEnabled
				tbPan.Enabled = buttonsEnabled
				tbScrollPages.Enabled = buttonsEnabled
				tbCompositeTool.Enabled = buttonsEnabled
				' Zoom
				zoomOutStripButton.Enabled = buttonsEnabled
				zoomTextBox.Enabled = buttonsEnabled
				zoomInStripButton.Enabled = buttonsEnabled
				tbZoomModes.Enabled = buttonsEnabled

				If zoomTextBox.Enabled Then
					UpdateTextBoxZoom()
				End If
			End If

			If UseImageViewerImages AndAlso _imageViewer IsNot Nothing Then
				SelectedPageIndex = e.FocusedIndex
			End If
		End Sub


		Private Sub imageViewer_ZoomChanged(sender As Object, e As ZoomChangedEventArgs)
			UpdateTextBoxZoom()

			If AssociatedZoomTrackBar IsNot Nothing Then
				AssociatedZoomTrackBar.Value = Math.Min(_imageViewer.Zoom, AssociatedZoomTrackBar.Maximum)
				toolTip.SetToolTip(AssociatedZoomTrackBar, AssociatedZoomTrackBar.Value.ToString(CultureInfo.InvariantCulture) & "%")
			End If

			_imageScaleSelected.Checked = False
			Select Case _imageViewer.SizeMode
				Case ImageSizeMode.BestFit
					_imageScaleSelected = bestFitToolStripMenuItem
					Exit Select
				Case ImageSizeMode.FitToHeight
					_imageScaleSelected = fitToHeightToolStripMenuItem
					Exit Select
				Case ImageSizeMode.FitToWidth
					_imageScaleSelected = fitToWidthToolStripMenuItem
					Exit Select
				Case ImageSizeMode.Normal
					_imageScaleSelected = normalToolStripMenuItem
					Exit Select
				Case ImageSizeMode.PixelToPixel
					_imageScaleSelected = pixelToPixelToolStripMenuItem
					Exit Select
				Case ImageSizeMode.Zoom
					_imageScaleSelected = scaleToolStripMenuItem
					Exit Select
			End Select

			_imageScaleSelected.Checked = True
		End Sub

		Private Sub VisualTool_ImageLoadingException(sender As Object, e As ExceptionEventArgs)
			MessageBox.Show(e.Exception.Message, "Visual tool")
		End Sub

		#End Region


		#Region "Event handlers of image collection (not thread safe)"

		' Handler of the ImageViewer.Images.CollectionChanged event (not thread safe).
		Private Sub Images_CollectionChanged(sender As Object, e As ImageCollectionChangeEventArgs)
			If UseImageViewerImages Then
				labelPagesCount.Text = PageCount.ToString()
			End If
		End Sub

		' Handler of the ImageViewer.Images.CollectionChanged event (thread safe).
		Private Sub Images_CollectionChangedSafely(sender As Object, e As ImageCollectionChangeEventArgs)
			If _imageViewer.InvokeRequired Then
				_imageViewer.Invoke(_images_CollectionChangedEventThreadSafe, New Object() {sender, e})
			Else
				Me.Images_CollectionChanged(sender, e)
			End If
		End Sub

		#End Region


		#Region "Event handlers of visual tool"

		Private Sub visualTool_RectangularSelectionChanged(sender As Object, e As SelectionChangedEventArgs)
			visualToolInfo.Text = String.Format(CultureInfo.InvariantCulture, "X={0}, Y={1}, Width={2}, Height={3}", e.Rectangle.X, e.Rectangle.Y, e.Rectangle.Width, e.Rectangle.Height)
		End Sub

		Private Sub visualTool_CustomSelectionChanged(sender As Object, e As CustomSelectionChangedEventArgs)
			Dim bbox As Rectangle = Rectangle.Round(e.Selection.GetBoundingBox())
			Dim newValue As String = String.Format(CultureInfo.InvariantCulture, "Bounding box: X={0}, Y={1}, Width={2}, Height={3}", bbox.X, bbox.Y, bbox.Width, bbox.Height)
			If newValue <> visualToolInfo.Text Then
				visualToolInfo.Text = newValue
			End If
		End Sub

		#End Region


		Private Sub UpdateSelectedPageIndex(index As Integer)
			If PageCount = 0 Then
				textBoxPages.Text = ""
				Return
			End If

			If index > PageCount - 1 Then
				index = PageCount - 1
			End If

			If index < 0 Then
				If Not UseImageViewerImages OrElse (_imageViewer.FocusedIndex <> index) Then
					index = 0
				End If
			End If

			_selectedPageIndex = index
			textBoxPages.Text = [String].Format(CultureInfo.InvariantCulture, "{0}", _selectedPageIndex + 1)

			RaiseEvent PageIndexChanged(Me, New PageIndexChangedEventArgs(index))

			If UseImageViewerImages AndAlso _imageViewer.FocusedIndex <> index Then
				_imageViewer.FocusedIndex = index
			End If
		End Sub

		Private Sub _associatedZoomTrackBar_ValueChanged(sender As Object, e As EventArgs)
			_imageViewer.Zoom = AssociatedZoomTrackBar.Value
		End Sub

		Private Sub _associatedZoomTrackBar_Scroll(sender As Object, e As EventArgs)
			_imageViewer.SizeMode = ImageSizeMode.Zoom
			_imageViewer.Zoom = AssociatedZoomTrackBar.Value
		End Sub

		Public Sub Reset()
			Instrument_Click(tbNone, Nothing)
		End Sub

		#End Region



		#Region "Events"

		<Browsable(True)> _
		Public Event OpenFile As EventHandler

		<Browsable(True)> _
		Public Event SaveFile As EventHandler

		<Browsable(True)> _
		Public Event Scan As EventHandler

		<Browsable(True)> _
		Public Event Print As EventHandler

		<Browsable(True)> _
		Public Event PageIndexChanged As PageIndexChangedEventHandler

		#End Region



		#Region "Delegates"

		Public Delegate Sub PageIndexChangedEventHandler(sender As Object, e As PageIndexChangedEventArgs)

		Private Delegate Sub Images_CollectionChangedThreadSafeDelegate(sender As Object, e As ImageCollectionChangeEventArgs)
		Private _images_CollectionChangedEventThreadSafe As Images_CollectionChangedThreadSafeDelegate
		Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
			target = value
			Return value
		End Function

		#End Region


	End Class
End Namespace
